#include "cDate_t.h"
#include <time.h>
#include <iostream>
#include <iomanip>

using namespace std;

//number of days in each month in leap and not leap years
const int cDate_t::numOfDaysInEachMonth[2][12] = {
	                                     {31,28,31,30,31,30,31,31,30,31,30,31},   
                                         {31,29,31,30,31,30,31,31,30,31,30,31}   
												};
//month names 
const char* cDate_t::monthName[12] = {"Jan","Feb","Mar","Apr","May","Jun",
                                      "Jul","Aug","Sep","Oct","Nov","Dec"};
//weekday names
const char * cDate_t::weekday[7] = { "Sunday", "Monday",
                                     "Tuesday", "Wednesday",
                                     "Thursday", "Friday", "Saturday"};



//*****************************************************************************
//default CTOR from current time
//*****************************************************************************
cDate_t::cDate_t()
{
	time_t time_date;
	struct tm* 	current_time;

	time_date = time(0);	
    current_time = localtime(&time_date);

	year =current_time->tm_year + 1900;
	month = current_time->tm_mon + 1;
	day = current_time->tm_mday;
	leap = (year%4==0);
}

//*****************************************************************************
//copy CTOR
//*****************************************************************************
cDate_t::cDate_t(const cDate_t& d)
{
	year = d.year;
	month = d.month;
	day = d.day;
	leap = d.leap;
}

//*****************************************************************************
//CTOR from year (>= 1900)
//*****************************************************************************
cDate_t::cDate_t(const int ye)
{
	if (ye<1900)
	{
		cout << "ERROR: year must be greater then 1899\n";
		exit(1);
	}

	year = ye;
	month = 1;
	day =1;
	leap = (ye%4==0);
}

//*****************************************************************************
//CTOR from year (>= 1900) and month (1-12)
//*****************************************************************************
cDate_t::cDate_t(const int ye, const int mo)
{
	if ((ye<1900)||(mo<1)||(mo>12))
	{
		cout << "ERROR: year must be greater then 1899\n";
		cout << "       month range is from 1 to 12\n";
		exit(1);
	}

	year = ye;
	month = mo;
	day = 1;
	leap = (ye%4==0);
}

//*****************************************************************************
//CTOR from year (>= 1900), month (1-12) and day (1-31)
//  "Thirty days hath September,
//   April, June, and November:
//   All the rest have thirty-one,
//   Except for February,
//   Which hath twenty-eight days clear,
//   And twenty-nine in each leap year."
//*****************************************************************************
cDate_t::cDate_t(const int ye, const int mo, const int da)
{
	leap = (ye%4==0);

	if ((ye<1900)||(mo<1)||(mo>12)||(da > numOfDaysInEachMonth[leap][mo-1]))
	{
		cout << "ERROR: year must be greater then 1899\n";
		cout << "       month range is from 1 to 12\n";
		cout << "       days range is from 1 to MAX in appropriate month\n";
		exit(1);
	}

	year = ye;
	month = mo;
	day = da;
}

//*****************************************************************************
//assignment operator
//*****************************************************************************
const cDate_t& cDate_t::operator=(const cDate_t& d)
{
	if (this != &d)
	{
		year = d.year;
		month = d.month;
		day = d.day;
		leap = d.leap;
	}

	return *this;
}

//*****************************************************************************
//DTOR
//*****************************************************************************
cDate_t::~cDate_t()
{
}

//*****************************************************************************
//set year (greater then 1899) in existing object
//return 1 if succeeded, 0 otherwise
//*****************************************************************************
int cDate_t::setYear(const int ye)
{
	if (ye<1900)
	{
		cout << "ERROR: year must be greater then 1899\n";
		return 0;
	} 
	else if (day > numOfDaysInEachMonth[ye%4==0][month-1])
	{
		cout << "ERROR: the number of days is illegal in this year\n";
		return 0;
	}

	year = ye;
	leap = (ye%4==0);	

	return 1;
}

//*****************************************************************************
//set month (1-12) in existing object
//return 1 if succeeded, 0 otherwise
//*****************************************************************************
int cDate_t::setMonth(const int mo)
{
	if ((mo<1)||(mo>12))
	{
		cout << "ERROR: month range is from 1 to 12\n";
		return 0;
	} 
	else if (day > numOfDaysInEachMonth[leap][mo-1])
	{
		cout << "ERROR: the number of days is illegal in this month\n";
		return 0;
	}

	month = mo;

	return 1;
}

//*****************************************************************************
//set day (1-MAX) in existing object
//return 1 if succeeded, 0 otherwise
//*****************************************************************************
int cDate_t::setDay(const int da)
{
	if (day > numOfDaysInEachMonth[leap][month-1])
	{
		cout << "ERROR: the number of days is illegal in this month\n";
		return 0;
	}

	day = da;

	return 1;
}

//*****************************************************************************
//print out date object in three formats
//format=1: dd/mmm/yyyy     example: 01/Apr/2010
//format=2: dd/mm/yyyy      example: 01/04/2010      Europian
//format=3: mm/dd/yyyy		example: 04/01/2010      American
//*****************************************************************************
void cDate_t::printOut(const int frmt) const
{
	cout << setfill('0');

	switch (frmt)
	{
	case 1:
		cout << setw(2) << day << "/" << setw(3) << monthName[month-1] << "/" 
			                                        << setw(4) << year << endl;
		break;
	case 2:					
		cout << setw(2) << day << "/" << setw(2) << month << "/" 
			                                        << setw(4) << year << endl;
		break;
	case 3:					
		cout << setw(2) << month << "/" << setw(2) << day << "/" 
			                                        << setw(4) << year << endl;
		break;
	default:
		cout << "ERROR: format value must be 1,2 or 3\n";
	}
}

//*****************************************************************************
//get year
//*****************************************************************************
int cDate_t::getYear() const
{
	return year;
}

//*****************************************************************************
//get month
//*****************************************************************************
int cDate_t::getMonth() const
{
	return month;
}

//*****************************************************************************
//get day
//*****************************************************************************
int cDate_t::getDay() const
{
	return day;
}

//*****************************************************************************
//get day of year (1-365)
//*****************************************************************************
int cDate_t::getDayOfYear() const
{
	int sum=0;	
	for(int i=0;i<month-1;++i)
	{
		sum+=numOfDaysInEachMonth[leap][i];
	}
	sum+=day;

	return sum;
}

//*****************************************************************************
//is  year leap?
//*****************************************************************************
bool cDate_t::isYearLeap() const
{
	return leap;
}

//*****************************************************************************
//return name of day (Sun,Mon,... )
//*****************************************************************************
const char* cDate_t::getWeekdayName() const
{
  time_t rawtime;
  struct tm * timeinfo;

  /* get current timeinfo and modify it to the user's choice */
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  timeinfo->tm_year = year - 1900;
  timeinfo->tm_mon = month - 1;
  timeinfo->tm_mday = day;

  /* call mktime: timeinfo->tm_wday will be set */
  mktime ( timeinfo );

  return weekday[timeinfo->tm_wday];
}

//*****************************************************************************
//return name of month (Jan,Feb,... )
//*****************************************************************************
const char* cDate_t::getMonthName() const
{
	return monthName[month-1];
}

